package columnd

import (
	"time"

	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/ddd/repo/mgorepo"

	"github.com/globalsign/mgo"
	"github.com/globalsign/mgo/bson"
	"github.com/pkg/errors"
	ccolumnd "gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/columnd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/common"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/repo/mgorepo/baser"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/ddd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/log"
)

// CreDomainOption 创建域配置
func CreDomainOption() ccolumnd.DomainOption {
	mgorepo.RegColForIndex(&collColumn{})
	mgorepo.RegColForIndex(&collExtraType{})
	return ccolumnd.DomainOption{
		ColumnRepo:    &columnRepo{},
		ExtraTypeRepo: &extraTypeRepo{},
	}

}

type columnRepo struct {
	baser.BaseRepo
}

// 新增信息
func (r *columnRepo) AddColumn(ctx ddd.Context, column ccolumnd.ColumnDesc) (id string, err error) {
	var cc collColumn
	cc.FullDesc(column)
	cc.CreTime = time.Now()
	cc.Creator = ctx.UID()
	cc.Updater = cc.Creator
	cc.UpdateTime = cc.CreTime
	cc.ColumnID = bson.NewObjectId().Hex()
	cc.Status = 0
	return cc.ColumnID, r.DBInsert(ctx, cc)

}

// 获取指定栏目聚合
func (r *columnRepo) GetColumn(ctx ddd.Context, columnid string) (ca *ccolumnd.ColumnAggregate, err error) {
	a, err := r.GetByCollAggregate(ctx, &collColumn{ColumnID: columnid})
	if err != nil {
		if err == mgo.ErrNotFound {
			return nil, nil
		}
		return nil, errors.Wrapf(err, "获取指定栏目(%v)失败", columnid)
	}
	ca = a.(*ccolumnd.ColumnAggregate)
	return
}

// 分页获取信息列表：根据唯一标识获取下一页指定数量的信息实体集合
// total 总数量
func (r *columnRepo) QueryPage(ctx ddd.Context, sch ccolumnd.ColumnSearch, pi common.PageInfo) (npi common.PageResult, result []ccolumnd.ColumnAggregate, err error) {
	query := bson.M{}
	if sch.Key != "" {
		query["name"] = bson.M{"$regex": sch.Key}
	}
	if sch.PID != "" {
		query["parentID"] = sch.PID
	}
	if len(sch.Status) > 0 {
		query["status"] = bson.M{"$in": sch.Status}
	}
	if sch.Range == 1 {
		// 需要包含系统栏目
		if sch.Org != "" {
			query["$or"] = []bson.M{
				bson.M{
					"org":   sch.Org,
					"owner": sch.Owner,
				},
				bson.M{
					"org":   "",
					"owner": "",
					"kind":  ccolumnd.ColumnKindSys,
					"isOrg": 1,
				},
			}
		} else {
			query["org"] = sch.Org
			query["owner"] = sch.Owner
		}
	} else {
		query["org"] = sch.Org
		query["owner"] = sch.Owner
	}
	var cs []collColumn

	npi, err = r.DBQueryPage(ctx, collNameColumn, pi, "_id", query, nil, []string{"-id"}, &cs)

	if err != nil {
		if err == mgo.ErrNotFound {
			err = nil
			npi.End = 1
			return
		}
		err = errors.Wrapf(err, "获取指定栏目列表失败.查询条件:%v 分页信息：%v", sch, pi)
		return
	}
	if len(cs) == 0 {
		npi.End = 1
		return
	}
	result = make([]ccolumnd.ColumnAggregate, 0, len(cs))
	for _, c := range cs {
		ia := c.ToColumnAggregate()
		// 初始化聚合
		ia.Init(ia, r.AggregateRoot(), c.CollID())
		result = append(result, *ia)
	}
	return
}

// 锁定栏目
func (r *columnRepo) Lock(ctx ddd.Context, columnid string) error {
	update := bson.M{
		"status": ccolumnd.CStatusLock,
	}
	err := r.DBUpdateID(ctx, collNameColumn, columnid, update)
	if err != nil {
		return errors.Wrapf(err, "锁定栏目(%v)失败", columnid)
	}
	_, _ = r.RefeshCache(ctx, &collColumn{ColumnID: columnid})
	return nil
}

// 解锁栏目
func (r *columnRepo) UnLock(ctx ddd.Context, columnid string) error {
	update := bson.M{
		"status": ccolumnd.CStatusNormal,
	}
	err := r.DBUpdateID(ctx, collNameColumn, columnid, update)
	if err != nil {
		return errors.Wrapf(err, "解锁栏目(%v)失败", columnid)
	}
	_, _ = r.RefeshCache(ctx, &collColumn{ColumnID: columnid})
	return nil
}

// 删除信息 标记删除
func (r *columnRepo) DeleteColumn(ctx ddd.Context, columnid string) error {
	update := bson.M{
		"status":     -1,
		"deleter":    ctx.UID(),
		"deleteTime": time.Now(),
	}
	err := r.DBUpdateID(ctx, collNameColumn, columnid, update)
	if err != nil {
		return errors.Wrapf(err, "删除栏目(columnid)失败")
	}
	err = r.DeleteCache(ctx, &collColumn{ColumnID: columnid})
	if err != nil {

		log.Warnf("删除信息%v缓存时失败：%v", columnid, err)
	}
	return nil
}

// 修改信息描述
func (r *columnRepo) UpdateDesc(ctx ddd.Context, columnid string, column *ccolumnd.ColumnDesc) error {
	update := bson.M{
		"name":       column.Name,
		"shortName":  column.ShortName,
		"kind":       column.Kind,
		"owner":      column.Owner,
		"org":        column.Org,
		"icon":       column.Icon,
		"page":       column.Page,
		"banner":     column.Banner,
		"desc":       column.Desc,
		"parentID":   column.ParentID,
		"updater":    ctx.UID(),
		"updateTime": time.Now(),
	}
	return r.DBUpdateCollAggregate(ctx, &collColumn{ColumnID: columnid}, update)
}

// 修改控制参数
func (r *columnRepo) UpdateCtlParam(ctx ddd.Context, columnid string, column *ccolumnd.ColumnCtlParam) error {
	update := bson.M{
		"isColReply":       column.IsColReply,
		"isInfoChk":        column.IsInfoChk,
		"isReply":          column.IsReply,
		"isChk":            column.IsChk,
		"allowIntCode":     column.AllowIntCode,
		"isSubmit":         column.IsSubmit,
		"isPublic":         column.IsPublic,
		"isOrg":            column.IsOrg,
		"infoMode":         column.InfoMode,
		"prohibitPostInfo": column.ProhibitPostInfo,
		"infourl":          column.Infourl,
		"updater":          ctx.UID(),
		"updateTime":       time.Now(),
	}

	return r.DBUpdateCollAggregate(ctx, &collColumn{ColumnID: columnid}, update)

}

// 改变栏目包含的发布信息数量
// num 大于0增加数量 小于0 减少数量 ，最终值最小为0
func (r *columnRepo) UpdatePubInfoNum(ctx ddd.Context, columnid string, num int) error {

	update := bson.M{
		"$inc": bson.M{
			"pubNum": num,
		},
	}
	err := r.DBUpdateID(ctx, collNameColumn, columnid, update, true)
	if err != nil {
		return err
	}
	if num < 0 {
		// 检查并更新小于0的栏目的数量
		err1 := r.DBUpdate(ctx, collNameColumn, bson.M{
			"_id":    columnid,
			"pubNum": bson.M{"$lt": 0},
		}, bson.M{"pubNum": 0})

		if err1 != nil {
			log.Warnf("检查栏目(%v)发布数量为负数时更新为0失败:%v", columnid, err1)
		}
	}
	_, err = r.RefeshCache(ctx, &collColumn{ColumnID: columnid})
	return err
}

// 改变栏目包含的发布信息数量
// num 大于0增加数量 小于0 减少数量 ，最终值最小为0
func (r *columnRepo) UpdatePubInfoNum2(ctx ddd.Context, columnid string, num int) error {

	update := bson.M{
		"$inc": bson.M{
			"pubNum":  num,
			"infoNum": num,
		},
	}
	err := r.DBUpdateID(ctx, collNameColumn, columnid, update, true)
	if err != nil {
		return err
	}
	if num < 0 {
		// 检查并更新小于0的栏目的数量
		err1 := r.DBUpdate(ctx, collNameColumn, bson.M{
			"_id": columnid,
			"$or": bson.D{
				{Name: "pubNum", Value: bson.M{"$lt": 0}},
				{Name: "infoNum", Value: bson.M{"$lt": 0}},
			},
		}, bson.M{"$max": bson.M{"pubNum": 0, "infoNum": 0}}, true)
		if err1 != nil && err1 != mgo.ErrNotFound {
			log.Warnf("检查栏目(%v)数量为负数时更新为0失败:%v", columnid, err1)
		}
	}
	_, err = r.RefeshCache(ctx, &collColumn{ColumnID: columnid})
	return err
}

// 改变栏目包含的信息数量
// num 大于0增加数量 小于0 减少数量 ，最终值最小为0
func (r *columnRepo) UpdateInfoNum(ctx ddd.Context, columnid string, num int) error {

	update := bson.M{
		"$inc": bson.M{
			"infoNum": num,
		},
	}
	err := r.DBUpdateID(ctx, collNameColumn, columnid, update, true)
	if err != nil {
		return err
	}
	// 检查并更新小于0的栏目的数量
	err1 := r.DBUpdate(ctx, collNameColumn, bson.M{
		"_id":    columnid,
		"pubNum": bson.M{"$lt": 0},
	}, bson.M{"infoNum": 0}, true)
	if err1 != nil && err1 != mgo.ErrNotFound {
		log.Warnf("检查栏目(%v)发布数量为负数时更新为0失败:%v", columnid, err1)
	}
	_, err = r.RefeshCache(ctx, &collColumn{ColumnID: columnid})
	return err
}

// 修改信息扩展信息
func (r *columnRepo) UpdateExtras(ctx ddd.Context, columnid string, column []ccolumnd.ColumnExtraItem) error {
	var ces []columnExtraItem

	for _, v := range column {
		t := &columnExtraItem{}
		t.Full(v)
		ces = append(ces, *t)
	}

	update := bson.M{
		"extras": ces,
	}

	return r.DBUpdateCollAggregate(ctx, &collColumn{ColumnID: columnid}, update)
}

// 删除指定信息
func (r *columnRepo) DeleteByID(ctx ddd.Context, columnid string) error {
	update := bson.M{
		"status": -1,
	}
	err := r.DBUpdateID(ctx, collNameColumn, columnid, update)
	if err != nil {
		return err
	}
	err = r.DeleteCache(ctx, &collColumn{ColumnID: columnid})
	if err != nil {
		log.Warnf("删除栏目%v缓存时失败：%v", columnid, err)
	}
	return nil
}

// 恢复指定信息
func (r *columnRepo) Recover(ctx ddd.Context, columnid string) error {
	update := bson.M{
		"status": ccolumnd.CStatusNormal,
	}
	err := r.DBUpdateID(ctx, collNameColumn, columnid, update)
	if err != nil {
		return err
	}
	return nil
}

// 彻底删除指定信息
func (r *columnRepo) DestroyByID(ctx ddd.Context, columnid string) error {
	return r.DestroyByCollAggregate(ctx, &collColumn{ColumnID: columnid})
}

// 获取系统或用户或组织栏目树
func (r *columnRepo) ColumnTree(ctx ddd.Context, org, owner string) (result []ccolumnd.ColumnAggregate, err error) {
	query := bson.M{
		"kind":   bson.M{"$in": []ccolumnd.ColumnKind{ccolumnd.ColumnKindCommon, ccolumnd.ColumnKindSys, ccolumnd.ColumnKindInteractive}},
		"status": bson.M{"$ne": ccolumnd.CStatusDelete},
		"org":    org,
		"owner":  owner,
	}
	return r.queryColumns(ctx, query)
}

// 获取系统开放给组织的所有栏目
func (r *columnRepo) ColumnSysOrgTree(ctx ddd.Context) (result []ccolumnd.ColumnAggregate, err error) {
	query := bson.M{
		"kind":   bson.M{"$in": []ccolumnd.ColumnKind{ccolumnd.ColumnKindSys}},
		"status": bson.M{"$ne": ccolumnd.CStatusDelete},
		"org":    "",
		"owner":  "",
		"isOrg":  1,
	}
	return r.queryColumns(ctx, query)
}

func (r *columnRepo) ExistName(ctx ddd.Context, org, owner, parentID, columnid, name string) (ok bool, err error) {
	query := bson.M{
		"status":   0,
		"name":     name,
		"org":      org,
		"owner":    owner,
		"parentID": parentID,
	}
	if columnid != "" {
		query["_id"] = bson.M{"$ne": columnid}
	}
	return r.DBExists(ctx, collNameColumn, query)
}
func (r *columnRepo) Children(ctx ddd.Context, columnid string) (result []ccolumnd.ColumnAggregate, err error) {
	query := bson.M{
		"parentID": columnid,
		"status":   0,
	}
	return r.queryColumns(ctx, query)
}
func (r *columnRepo) queryColumns(ctx ddd.Context, query bson.M) (result []ccolumnd.ColumnAggregate, err error) {
	var ics []collColumn
	if err = r.DBQuery(ctx, collNameColumn, query, nil, nil, &ics); err != nil {
		return nil, errors.Wrapf(err, "queryColumns 查找栏目失败")
	}

	result = make([]ccolumnd.ColumnAggregate, 0, len(ics))
	for _, c := range ics {
		ia := c.ToColumnAggregate()
		// 初始化聚合
		ia.Init(ia, r.AggregateRoot(), c.ColumnID)
		result = append(result, *ia)
	}
	return
}

// 是否存在子栏目
func (r *columnRepo) ExistChildren(ctx ddd.Context, columnid string) (ok bool, err error) {
	query := bson.M{
		"parentID": columnid,
		"status":   0,
	}
	return r.DBExists(ctx, collNameColumn, query)
}
